import { TFile, normalizePath } from 'obsidian';

/**
 * 表示一个在笔记中找到的链接
 */
interface ParsedLink {
    /** 链接的原始完整文本，例如 `[[目标笔记]]` 或 `[描述](http://example.com)` */
    rawText: string;
    /** 链接指向的目标（内部链接为笔记名或路径，外部链接为URL） */
    target: string;
    /** 链接类型：'internal'（内部链接）或 'external'（外部链接） */
    type: 'internal' | 'external';
    /** 链接在文档中出现的行号（从1开始计数） */
    lineNumber: number;
    /** 链接在该行中的起始位置（索引，从0开始） */
    position: number;
    /** 链接的显示文本（别名），仅对部分格式有效 */
    alias?: string;
}

/**
 * 解析指定的笔记文件，获取其所有的内部链接和外部链接及其行号。
 * @param app Obsidian App 对象
 * @param file 要解析的笔记文件
 * @returns 包含所有解析到的链接信息的数组
 */
export async function getLinksWithoutMetadata(app: any, file: TFile): Promise<ParsedLink[]> {
    const links: ParsedLink[] = [];

    // 1. 读取文件内容
    const content = await app.vault.read(file);
    const lines = content.split('\n');

    // 定义匹配链接的正则表达式
    // 匹配Obsidian内部链接： [[...]] 或 [[...|...]]
    const wikiLinkRegex = /(?<!\!)\[\[([^[\]]+?)(?:\|([^[\]]+))?\]\]/g;
    // 匹配标准Markdown外部链接： [...](...)
    const mdLinkRegex = /(?<!\!)\[([^[\]]*?)\]\(([^)]+)\)/g;

    // 2. 逐行解析
    for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
        const line = lines[lineIndex];
        let match;

        // 检查当前行是否在代码块内（简易判断，避免匹配代码块中的链接）
        if (isInsideCodeBlock(lines, lineIndex)) {
            continue;
        }

        // 匹配并提取WikiLinks (内部链接)
        while ((match = wikiLinkRegex.exec(line)) !== null) {
            links.push({
                rawText: match[0],
                target: match[1].trim(), // 链接目标（笔记名或路径）
                type: 'internal',
                lineNumber: lineIndex, // 行号从0开始
                position: match.index,
                alias: match[2]?.trim() // 别名（如果有）
            });
        }

        // 匹配并提取Markdown链接 (通常是外部链接，也可能链接到内部资源)
        while ((match = mdLinkRegex.exec(line)) !== null) {
            const url = match[2].trim();
            // 简单启发式判断：如果URL以http/https开头或包含常见网络协议，则为外部链接
            // 注意：此判断可能不完美，Markdown链接也可用于链接本地文件
            const isExternal = /^(https?:|ftp:|mailto:)/.test(url) || !url.startsWith('#');
            links.push({
                rawText: match[0],
                target: url,
                type: isExternal ? 'external' : 'internal', // 可根据需要调整判断逻辑
                lineNumber: lineIndex + 1,
                position: match.index,
                alias: match[1]?.trim()
            });
        }
    }

    return links;
}

/**
 * 简易判断指定行是否位于Markdown代码块内。
 * 通过分析之前行的代码块标记来实现。
 * @param lines 文档的所有行
 * @param lineIndex 当前行的索引
 * @returns 如果该行在代码块内，返回true
 */
function isInsideCodeBlock(lines: string[], lineIndex: number): boolean {
    let inCodeBlock = false;
    // 只需遍历到当前行即可
    for (let i = 0; i <= lineIndex; i++) {
        const line = lines[i];
        // 检查是否是一个代码块的开始或结束（```xxx 或 ~~~xxx）
        if (/^\s*`{3,}\w*\s*$/.test(line) || /^\s*~{3,}\w*\s*$/.test(line)) {
            inCodeBlock = !inCodeBlock; // 遇到代码块标记则切换状态
        }
    }
    return inCodeBlock;
}